<template>
  <div class="clearfix">
    <a-upload
      v-model:file-list="fileList"
      :action="uploadPathUrl"
      :headers="{ assessToken: useUserStore().token }"
      accept="image/*"
      :list-type="!props.text ? 'picture-card' : 'text'"
      v-bind="props.componentProps"
      :before-upload="beforeUpload"
      @preview="handlePreview"
      @change="handleChange"
      @remove="handleRemove"
    >
      <div v-if="canUploadMore && !props.text">
        <plus-outlined />
        <div style="margin-top: 8px">{{ upload }}</div>
      </div>
      <slot v-else></slot>
    </a-upload>
    <a-modal
      width="600px"
      :body-style="{ height: '600px' }"
      :visible="previewVisible"
      :title="previewTitle"
      :footer="null"
      @cancel="handleCancel"
    >
      <img class="w-full h-full object-contain" alt="example" :src="previewImage" />
    </a-modal>
  </div>
</template>

<script setup lang="ts">
  import { PlusOutlined } from '@ant-design/icons-vue';
  import { message } from 'ant-design-vue';
  import { publicPathUrl, uploadPathUrl } from '@/utils/common';
  import { useUserStore } from '@/store/modules/user';
  import { getFileHttpUrl } from '@/utils/urlUtils';
  import { ResultEnum } from '@/enums/httpEnum';

  const props = defineProps({
    componentProps: {
      type: Object,
      default: () => ({}),
    },
    imageStr: {
      type: String,
      default: () => '',
    },
    maxFileSizeMb: {
      type: Number,
      default: 20,
    },
    upload: {
      type: String,
      default: () => 'upload',
    },
    text: {
      type: Boolean,
      default: false,
    },
  });
  const { imageStr, componentProps, maxFileSizeMb, upload } = toRefs(props);
  const previewVisible = ref(false);
  const previewImage = ref('');
  const previewTitle = ref('');
  const fileList = ref<{ [x: string]: any }[]>([]);
  const allowedFileTypes = ref(['image/jpeg', 'image/png']);
  const emit = defineEmits(['onChangeUpload']);

  const canUploadMore = computed(() => {
    const { maxCount } = unref(componentProps);
    return !maxCount || (maxCount && fileList.value.length < maxCount);
  });

  const handleCancel = () => {
    previewVisible.value = false;
    previewTitle.value = '';
  };

  const isAllowedFileType = (fileType: string) => allowedFileTypes.value.includes(fileType);

  const beforeUpload = (file: any) => {
    const isJpgOrPng = isAllowedFileType(file.type);
    if (!isJpgOrPng) {
      message.error('You can only upload JPG file!');
    }
    const isLtMax = file.size / 1024 / 1024 < maxFileSizeMb.value;
    if (!isLtMax) {
      message.error(`Image must smaller than ${maxFileSizeMb.value}MB!`);
    }
    return isJpgOrPng && isLtMax;
  };

  const extractUrl = (item: any, needPrefix: boolean) => {
    const hasPrefixUrl = item?.response?.data?.url || item?.url;
    return needPrefix ? hasPrefixUrl : hasPrefixUrl.split(publicPathUrl)[1];
  };

  const handleEmitOnChangeUpload = () => {
    const componentsProp = unref(componentProps);
    emit('onChangeUpload', fileList.value.map((item) => extractUrl(item, componentsProp?.needPrefix))?.toString());
  };

  const handleChange = (info: any) => {
    const res = info.file;
    if (res.status === 'uploading') {
      return;
    }
    if (res.status === 'done') {
      if (res.response.code === ResultEnum.SUCCESS) {
        fileList.value = fileList.value.map((item) => {
          return {
            status: 'done',
            url: item?.response?.data?.url ? getFileHttpUrl(item?.response?.data?.url) : item?.url,
          };
        });
        handleEmitOnChangeUpload();
      } else {
        message.error(res.response.msg);
      }
      return;
    }
    if (res.status === 'error') {
      message.error('upload error');
    }
  };

  const handleRemove = (file: any) => {
    const { url } = file;
    fileList.value = fileList.value.filter((item) => item.url !== url);
    handleEmitOnChangeUpload();
  };
  const handlePreview = (file: { [x: string]: any }) => {
    if (!file.url) {
      message.error('file url error');
      return;
    }
    previewImage.value = file.url;
    previewVisible.value = true;
    previewTitle.value = file.name || file.url.substring(file.url.lastIndexOf('/') + 1);
  };

  watchEffect(() => {
    const list = imageStr.value && imageStr.value?.split(',');
    if (list && list.length) {
      fileList.value = list.map((item) => {
        return { url: getFileHttpUrl(item) };
      });
    } else {
      fileList.value = [];
    }
  });
</script>

<style lang="less" scoped>
  :deep(.ant-upload-list) {
    min-height: 104px;
    .ant-upload-select-picture-card i {
      font-size: 32px;
      color: #999;
    }

    .ant-upload-select-picture-card .ant-upload-text {
      margin-top: 8px;
      color: #666;
    }

    .avatar-uploader > .ant-upload {
      width: 128px;
      height: 128px;
    }
  }
</style>
